<?php
require_once 'Kornak/Http/Crawler/UrlNormalizer.php';
require_once 'Zend/Log.php';

class Kornak_Http_Crawler_Scheduler
{
    const URL_STATUS_QUEUED = 1;
    const URL_STATUS_DONE   = 2;
    const URL_STATUS_ERROR  = 3;

    protected $_crawler;
    protected $_firstRequestTime = 0;
    protected $_stayWithin;
    protected $_timeLimit = 0;
    protected $_urls = array();
    protected $_urlsCount = 0;
    protected $_urlsCountLimit = 0;

    protected function _accept($url)
    {
        if (!empty($this->_stayWithin)) {
            return $this->_stayWithin == substr($url, 0, strlen($this->_stayWithin));
        }

        return true;
    }

    protected function _log($message, $level = Zend_Log::INFO)
    {
        $this->getCrawler()->log($message, $level);
    }

    public function __construct($crawler = null)
    {
        if (null !== $crawler) {
            $this->setCrawler($crawler);
        }
    }

    public function addUrl($url)
    {
        $urls = (array) $url;

        foreach ($urls as $url) {
            $url = Kornak_Http_Crawler_UrlNormalizer::normalize($url);

            if (!array_key_exists($url, $this->_urls) && $this->_accept($url)) {
                $this->_urls[$url] = array(
                    'status' => self::URL_STATUS_QUEUED,
                );
            }
        }

        return $this;
    }

    public function getNextUrl()
    {
        if (empty($this->_firstRequestTime)) {
            $this->_firstRequestTime = time();
        }

        if (0 < $this->_urlsCountLimit &&
            $this->_urlsCount >= $this->_urlsCountLimit) {
            $this->_log('URLs count limit reached', Zend_Log::DEBUG);
            return false;
        }
        if (0 < $this->_timeLimit &&
            $this->_firstRequestTime + $this->_timeLimit <= time()) {
            $this->_log('Time limit reached', Zend_Log::DEBUG);
            return false;
        }

        foreach ($this->_urls as $url => $data) {
            if (self::URL_STATUS_QUEUED == $data['status']) {
                $this->_urlsCount++;
                return $url;
            }
        }

        return false;
    }

    public function getCrawler()
    {
        if (null === $this->_crawler) {
            require_once 'Kornak/Http/Crawler/Scheduler/Exception.php';
            throw new Kornak_Http_Crawler_Scheduler_Exception('Crawler must be set before getting it.');
        }

        return $this->_crawler;
    }

    public function getTimeLimit()
    {
        return $this->_timeLimit;
    }

    public function getUrlsCountLimit()
    {
        return $this->_urlsCountLimit;
    }

    public function setCrawler(Kornak_Http_Crawler_Abstract $crawler)
    {
        $this->_crawler = $crawler;
        return $this;
    }

    public function setTimeLimit($seconds)
    {
        $this->_timeLimit = $seconds;
        return $this;
    }

    public function setUrlsCountLimit($count)
    {
        $this->_urlsCountLimit = $count;
        return $this;
    }

    public function setUrlStatus($url, $status)
    {
        $this->_urls[$url]['status'] = $status;
    }

    public function stayWithin($url)
    {
        $this->_stayWithin = $url;
        return $this;
    }
}
